#pragma once

class eFile
{
public:
    enum TYPE
    {
        RAW,
        PACK,
        EOE,
    };
};

class eFileMode
{
public:
    enum TYPE
    {
        READ = 0x01,
        WRITE = 0x02,
        APPEND = 0x04,

        TEXT = 0x10,
        BINARY = 0x20,

        RT = READ | TEXT,
        RB = READ | BINARY,
        WT = WRITE | TEXT,
        WB = WRITE | BINARY,
        AT = APPEND | TEXT,
        AB = APPEND | BINARY,
    };

    static const tChar* ToChar(eFileMode::TYPE mode);
};

class eFileSeek
{
public:
    enum TYPE
    {
        SET = 0,
        CUR = 1,
        END = 2
    };
};

class cFile
{
public:
	friend class cFileManager;
	virtual ~cFile(void) {};
	
	virtual eFile::TYPE GetType() = 0;

	// 
	virtual tInt Seek(tInt offset, eFileSeek::TYPE seek) = 0;
	virtual tUInt Tell(void) = 0;
	virtual tInt Eof(void) = 0;
    virtual tInt GetPosition() = 0;
	virtual tChar* GetBuffer() = 0;
	// read / write

	virtual tUInt Read(void *data, tInt data_len) = 0;
	virtual void Write(void *data, tInt data_len) = 0;

	virtual tChar* Gets(tChar *str, tInt str_len) = 0;
	virtual void Puts(const tChar *str) = 0;

	template<typename T> inline tUInt Read(T *data);
	template<typename T> inline void Write(T *data);
	template<typename T> inline tUInt operator >> (T &data);
	template<typename T> inline cFile* operator << (const T &data);


	// - for binary

	template<typename T> inline void ReadVectorB(T &r);
	template<typename T> inline void ReadListB(T &r);
	template<typename T> inline void ReadSetB(T &r);
	inline void ReadTextB(tChar *text);
	
	template<typename T> inline	void WriteVectorB(T &r);
	template<typename T> inline void WriteListB(T &r);
	template<typename T> inline void WriteSetB(T &r);
	virtual inline	void WriteTextB(const tChar *text);

    //

	tInt GetBufferSize() const { return m_filesize; }

//protected:
	cFile(void) { m_filesize = 0; }

    virtual bool Open(const tString& fullpath, eFileMode::TYPE mode, tBool alloc) = 0;
	virtual void Close() = 0;


protected:
    eFileMode::TYPE m_mode;
	tString m_fullpath;
	tInt m_filesize;
};


typedef tVector<cFile*> tFileVector;



// inline function

template<typename T> inline 
tUInt cFile::operator >> (T &data)
{
	return Read(&data);
}

template<typename T> inline 
cFile* cFile::operator << (const T &data)
{
	Write(&data);
	return this;
}

template<typename T> inline
tUInt cFile::Read(T *data)
{
	return Read((void *)data, sizeof(T));
}

template<typename T> inline
void cFile::Write(T *data)
{
	Write((void *)data, sizeof(T));
}



template<typename T> inline 
void cFile::ReadVectorB(T &r)
{
	tUInt size;
	(*this) >> size;

	r.resize(size);
	tUInt i,ni = size;
	for(i=0;i<ni;i++)
	{
		(*this) >> r[i];
	}
}

template<typename T> inline 
void cFile::ReadSetB(T &r)
{
	tUInt size;
	typename T::value_type v;
	(*this) >> size;
	tUInt i,ni = size;
	for(i=0;i<ni;i++)
	{
		(*this) >> v;
		r.insert(v);
	}
}


template<typename T> inline
void cFile::ReadListB(T &r)
{
	tUInt size;
	typename T::value_type v;
	(*this) >> size;
	tUInt i,ni = size;
	for(i=0;i<ni;i++)
	{
		(*this) >> v;
		r.push_back(v);
	}
}

inline 
void cFile::ReadTextB(tChar *text)
{
	tInt len;

	Read(&len, 4);
	Read(text, len+1);
}


template<typename T> inline
void cFile::WriteVectorB(T &r)
{
	tUInt size = r.size();
	(*this) << size;
	tUInt i,ni = size;
	for(i=0;i<ni;i++)
	{
		(*this) << r[i];
	}
}

template<typename T> inline
void cFile::WriteListB(T &r)
{
	tUInt size = r.size();
	(*this) << size;
	typename T::iterator it,et;
	it = r.begin();
	et = r.end();
	for(;it!=et;++it)
	{
		(*this) << (*it);
	}
}


template<typename T> inline
void cFile::WriteSetB(T &r)
{
	WriteListB(r);
}


inline 
void cFile::WriteTextB(const tChar *text)
{
	tInt len = (tInt)strlen(text);

	Write(&len, 4);
	Write((void*)text, len + 1);
}
